home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d26
/
typefast.arc
/
TYPEFAST.C
< prev
next >
Wrap
Text File
|
1989-11-27
|
14KB
|
493 lines
/*
* TYPEFAST
* Improve your typing the fun way
* by Steve Spearman druco!spear 11/18/86
*/
/* Fixes/Enhancements:
* by Dave Tutelman att!mtunb!dmt 2/5/89
* - Ported to MSDOS PCs (Turbo C & PCcurses).
* Compile with #define MSDOS.
* - Compile with #define WORDLIST, to use your own favorite words
* (in WORDLIST.H), instead of those built into WORDS.C.
* - Slowed down missiles so they stay visible @ >9600 baud.
* - Fudged highrow to allow more time for longer words.
*/
#include <stdio.h>
#include <curses.h>
/* non-int external functions used */
extern long time();
/*Declarations follow for non-int functions */
extern void screeninit(),getsetup(),checkhit(),showscore(),cleartarget();
#define MAXLEN 20 /*MAX word length */
#define MAXSIZE 30 /*MAX word length + some fudge */
#define MAXTARGET 10 /*MAX target words*/
#define MAXMISS 10 /*Number of missed words to end game */
#define MAXROW 23 /*Maximum row allowed */
#define boolean int
extern char *words[]; /* word list from other file */
extern int initwords(); /* word list initializer from other file */
struct word { /* the structure of each word on the screen*/
char text[MAXLEN]; /* word text */
int row; /* screen row position */
int col; /* screen column position */
int len; /* length of word */
boolean active; /* indicates if word is active or not */
};
struct word target[MAXTARGET];
/* the following are set in the 'getsetup' function */
int addtarget, /* Add a new target every x hits*/
movedown, /* move top row down every x hits */
movebottom, /* move botom row down every x hits */
startwords; /* Starting number of target words*/
int lowrow; /* lowest row number for a word */
int highrow; /* highest row number for a word */
/* internal variables */
int maxword; /* number of words in list */
int targets=0; /* total active targets */
int missed=0; /* total misses */
int total=0; /* total hits */
long strokes=0; /* total key stroke hits on words gotten*/
long allstrokes=0; /* total key stroke hits including bad*/
long starttime; /* time we started typing */
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
int c;
if (argc > 1) {
printf("Usage: %s \n", argv[0]);
exit(1);
}
initialize(); /* initialize curses */
getsetup(); /* set difficulty variables */
screeninit(); /* put up initial display */
maxword = initwords(); /* get the word list */
for (targets=0;targets < startwords; targets++) {
newtarget(targets); /* set up a target word */
}
starttime = time ((long *) 0);
while (missed < MAXMISS) {
targetmove();
refresh();
napms(600); /* suspend for so many milliseconds */
while ((c=getch()) >= 0) {
if (c == '\033') { /* ESCAPE */
doend(); /* end the game with states*/
}
checkhit(c);
}
}
move(21,0);
clrtoeol();
mvprintw(21,0,"END of Game: you missed the maximum %d words",missed);
doend();
}
/* DOEND
*
* Print out the ending statistics and exit gracefully
*/
int
doend()
{
mvprintw(22,0,"WPM on words typed correctly: %d",wpm(strokes));
printw(" WPM on all words typed: %d",wpm(allstrokes));
goodbye();
}
/* TARGETMOVE
*
* Moves all targets down a row and checks for any that have reached
* the bottom. If they have, it is counted and a new word is created.
*/
int
targetmove()
{
register int num;
for (num = 0; num < MAXTARGET; num++) {
if ( ! target[num].active)
continue;
if (movetarget(num)) {
newtarget(num);
missed++;
flash();
showscore();
}
}
}
/* CLEARWORD
*
* This function clears out the screen position of the word
* whose structure index is passed.
*/
void
clearword(num)
int num;
{
register int i;
move(target[num].row,target[num].col);
for (i=0; i < target[num].len; i++) {
addch(' ');
}
}
/* MOVETARGET
*
* This move the word structure whose index is passed down one row.
* If this move brings it to the edge of the screen, 1 is returned,
* otherwise, 0 is returned.
*/
int
movetarget(num)
int num;
{
clearword(num); /* clear the old word on screen */
target[num].row++; /* move down a row */
if(target[num].row >= MAXROW)
return(1);
mvprintw(target[num].row,target[num].col,target[num].text);
return(0);
}
/* NEWTARGET
*
* This function produces a new word structure in the structure whose
* index is passed. The word is chosen randomly and is placed randomly
* subject to constraints of screen placement and word proximity.
*/
int
newtarget(num)
int num;
{
register int i;
int wordno;
boolean bad;
int safety;
int samecol;
int _highrow; /* "Fudged" value of highrow for this word. We
* "give the typist a break" by one row for each
* "nominal" word of 5 characters in the word. */
wordno = (rand() % maxword); /* pick a word number */
strcpy(target[num].text,words[wordno]); /* copy the word into struct */
target[num].len=strlen(target[num].text); /* calculate length */
_highrow = highrow - target[num].len % 5; /* fudge _highrow */
bad = 1; /* flag that is cleared when we get a good word */
safety = 0;
while (bad) {
if (++safety > 5000)
error("New word not placable");
/* try to get a good row and column */
target[num].row= (rand() % (_highrow - lowrow + 1)) + lowrow;
target[num].col= (rand() % (80-target[num].len));
bad = 0;
/* check all other words to make sure no overlaps */
for (i=0; i< MAXTARGET; i++) {
if ( (! target[i].active) || (i == num) )
continue; /* don't check against self */
samecol = 0;
if ( (target[num].col <= target[i].col) &&
((target[num].col + target[num].len + 1) >= target[i].col))
samecol = 1; /* columns touch/overlap */
if ( (target[i].col <= target[num].col) &&
((target[i].col + target[i].len + 1) >= target[num].col))
samecol = 1; /* columns touch/overlap */
/* if columns overlap, check that the rows are */
/* separated by at least one blank to avoid problems */
/* with erasing or overwriting the other word during */
/* movement */
if ( samecol &&
(abs(target[num].row - target[i].row) < 2)) {
bad = 1;
break;
}
}
}
target[num].active = 1;
}
/* CHECKHIT
*
* This routine is passed a char each time one is typed. It collects
* words and compares the word typed with all words on the screen. If
* a match is found, the match lowest on the screen is considered hit
* and the routine gotit() is called to handle the hit.
*/
void
checkhit(c)
char c;
{
static int count = 0; /* character counter */
static char line[MAXSIZE]; /* the line you are typing */
int couldhit[MAXTARGET]; /* some booleans */
register int num;
register int row; /* holds row of number we shot */
int shot; /* holds the number of word we shot */
/* check for a word separator to end the word */
if ( (c != ' ') && (c != '\n') && ( c != '\r')) {
allstrokes++; /* count all key strokes */
/* character is not a separator, so just collect it */
if (count >= (MAXSIZE - 2)) /* if line too long, */
return; /* wait for next separator to begin again */
line[count++] = c;
return;
}
/* if we got here, we got a separator and have a word */
if ( count == 0 ) /* null word */
return;
line[count] = '\0';
count = 0; /*reset for next word */
shot = -1;
row = 0; /* keep track of largest row of word shot */
for (num=0;num < MAXTARGET; num++) {
if ( ! target[num].active ) /* only check active words */
continue;
/* check to see if the word matches */
if (strncmp(target[num].text,line,MAXSIZE) == 0) {
/* got a word! */
/* check if this is lower on screen than any others*/
if (target[num].row > row) {
row = target[num].row;
shot = num;
}
}
}
if ( shot == -1 )
return;
gotit(shot); /* handle the word we shot */
}
/* GOTIT
*
* We have gotten the word whose number is passed. Now produce any
* appropriate effects and clear out the word. Also, update score
* and create a new replacement word.
*/
int
gotit(num)
int num;
{
register int i,x,y;
char oldc = '\0';
char missile =
#ifdef MSDOS
0xEA; /* OMEGA looks like missile on PC screen */
#else
'^';
#endif
int incmove;
total++; /* keep track of words gotten */
x = target[num].col + (target[num].len / 2); /* center of word */
y = target[num].row; /* row of word */
strokes += target[num].len; /* count letters */
incmove = 1;
if (baudrate() < 9600)
incmove = 2;
if (baudrate() <= 1200)
incmove = 4;
if (baudrate() <= 300)
incmove = 8;
for (i = MAXROW ; i >= y; i -= incmove) { /* from the screen bottom to word */
if (i < MAXROW) /* restore previous position */
mvaddch(i + incmove,x,oldc);
oldc = mvinch(i,x); /* store old char for restore */
mvaddch(i,x,missile); /* put out 'missile' */
refresh();
if (baudrate() > 9600)
napms (100); /* if REAL fast, slow it down */
}
if (oldc)
mvaddch(i + incmove,x,oldc); /* clear last 'missile' */
if (((total % addtarget) == 0 ) && ((targets + 1) < MAXTARGET))
newtarget(targets++);
if (((total % movedown) == 0 ) && (highrow > (lowrow + 1)) )
lowrow++;
if (((total % movebottom) == 0 ) && (highrow < (MAXROW - 2)) )
highrow++;
showscore();
cleartarget(num);
newtarget(num);
}
/* CLEARTARGET
*
* Make an explosion where the word was if baudrate allows, and clear
* the screen at the word location
*/
void
cleartarget(num)
int num;
{
register int i;
int j;
char c;
#ifdef MSDOS
char explode[]={ '*', '#', 0xDB, 0xB2, 0xB1, 0xB0, ' '};
int jmax = 7; /* number of symbols in explosion */
int naptime = 70; /* 500 msec / 7 symbols ~= 70 msec */
#else
char explode[]={ '*', '#', ' '};
int jmax = 3; /* number of symbols in explosion */
int naptime = 160; /* 500 msec / 3 symbols ~= 160 msec */
#endif
for (j = 0; j < jmax; j++) {
if ((j < jmax) && (baudrate() < 4800))
continue;
c = explode [j];
move(target[num].row,target[num].col);
for (i=0;i< target[num].len; i++) {
addch(c);
}
refresh();
if (baudrate() > 9600)
napms (naptime);/* if REAL fast, slow it down */
}
}
/* SHOWSCORE
*
* Show the total words gotten and words missed
*/
void
showscore()
{
mvprintw(2,30,"Hits: %d",total);
mvprintw(2,42,"Misses: %d",missed);
}
/* SCREENINIT
*
* Initialize the screen for the game
*/
void
screeninit()
{
clear();
srand(time(0)); /* set up random numbers */
standout();
mvprintw(1,35,"**TYPEFAST**");
mvprintw(MAXROW,1,"<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>");
standend();
showscore();
refresh();
}
/* WPM
*
* Calculate total wpm by taking the number of key strokes passed,
* calculating elapsed time, and figuring 5 chars per word.
*/
int
wpm(tstrokes)
long tstrokes;
{
long totaltime;
float result;
int iresult;
totaltime = time((long *) 0);
totaltime -= starttime; /* figure total time in seconds */
if (totaltime < 1)
return(0);
result = (tstrokes * 60.0)/ (5.0 * totaltime);
iresult = (int) result;
return(iresult);
}
/* GETSETUP
*
* This routine sets up the initial screen and gives instructions,
* and prompts for game level. It then sets several game variables
* for number of targets, locations, and how often variables are
* changed to increase difficulty.
*/
void
getsetup()
{
char c;
clear();
standout();
mvprintw(0,0,"<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>");
mvprintw(MAXROW-1,0,"<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>");
mvprintw(5,30,"The TYPEFAST Game");
standend();
mvprintw(12,10,"Do you need instructions? Press y or n (no RETURN)");
refresh();
while (((c = getch()) != 'y') && (c != 'n')) ;
move(12,10);
clrtoeol();
if (c == 'y') {
move(8,0);
printw("Words will move down the screen toward the bottom. You must type\n");
printw("each word before it reaches the bottom. End each word you type with\n");
printw("a SPACE or a RETURN. When you successfully type a word in time a\n");
printw("new one will take its place somewhere on the screen. The number\n");
printw("of words will increase as you go along and the words will get closer\n");
printw("to the bottom of the screen. At the end your Words Per Minute is shown.\n");
}
standout();
mvprintw(16,10,"Press the letter of the level of difficult you wish (no RETURN)");
standend();
mvprintw(18,33,"1-Easy");
mvprintw(19,33,"2-Normal");
mvprintw(20,33,"3-Hard");
mvprintw(21,33,"q-Quit");
refresh();
while (1) {
c = getch();
if ((c >= '1') && (c <= '3'))
break;
if (c == 'q')
error("Game aborted as requested");
}
switch (c) {
case '1':
addtarget= 60; /*Add a new target every x hits*/
movedown= 50; /*move top row down every x hits */
movebottom=130; /*move botom row down every x hits */
startwords= 2; /*Starting target words*/
lowrow = 4; /* lowest row number for a word */
highrow = 15; /* highest row number for a word */
break;
case '2':
addtarget= 50; /*Add a new target every x hits*/
movedown= 50; /*move top row down every x hits */
movebottom=100; /*move botom row down every x hits */
startwords= 3; /*Starting target words*/
lowrow = 6; /* lowest row number for a word */
highrow = 17; /* highest row number for a word */
break;
case '3':
addtarget= 50; /*Add a new target every x hits*/
movedown= 30; /*move top row down every x hits */
movebottom= 60; /*move botom row down every x hits */
startwords= 5; /*Starting target words*/
lowrow = 10; /* lowest row number for a word */
highrow = 18; /* highest row number for a word */
break;
default:
error("Internal game switch error");
}
clear();
}